﻿using System;
using BasicFramework.Devices;
using BasicFramework.Devices.DirectX9;
using BasicFramework.Rendering.Buffer;
using BasicFramework.Rendering.Buffer.DirectX9;
using BasicFramework.Rendering.Primitives;
using BasicFramework.Rendering.Primitives.Indexes;
using BasicFramework.Rendering.Primitives.Vertizes;
using BasicFramework.Services.MeshLoader.Nodes;
using SlimDX;

namespace BasicFramework.Services.MeshLoader.Meshes
{
    // TODO:  ColorVertex durch Vertex Base class ersetzen
    public abstract class Mesh
    {

        #region Fields


        private MeshContainer container;
        private DeviceContextBase context;


        private Vector3 position; //mesh pos in collada file
        private Vector3 orientation;
        private Vector3 location; //instance pos in world

        private Matrix worldMatrix;
        private Matrix objectMatrix;

        private Matrix view;
        private Matrix projection;
        private float frameTime;


        private int verticeCount;
        private int indexCount;


        private DynamicPrimitiveBuffer<Index> indexBuffer;
        // TODO:  ColorVertex durch Vertex Base class ersetzen
        private DynamicPrimitiveBuffer<TexturedVertex> vertexBuffer;

        #endregion


        #region Properties

        public MeshContainer Container
        {
            get { return container; }
            set { container = value; }
        }

        public DeviceContextBase Context
        {
            get { return context; }
            set { context = value; }
        }

        public Vector3 Position
        {
            get { return position; }
            set { position = value; }
        }

        public Matrix WorldMatrix
        {
            get { return worldMatrix; }
            set { worldMatrix = value; }
        }

        public Matrix View
        {
            get { return view; }
            set { view = value; }
        }

        public Matrix Projection
        {
            get { return projection; }
            set { projection = value; }
        }

        public DynamicPrimitiveBuffer<TexturedVertex> VertexBuffer
        {
            get { return vertexBuffer; }
            internal set { this.vertexBuffer = value; }
        }

        public DynamicPrimitiveBuffer<Index> IndexBuffer
        {
            get { return indexBuffer; }
            internal set
            {
                this.indexBuffer = value;
            }
        }

        public Matrix ObjectMatrix
        {
            get { return objectMatrix; }
            set { objectMatrix = value; }
        }

        public int VerticeCount
        {
            get { return verticeCount; }
            set { verticeCount = value; }
        }

        public int IndexCount
        {
            get { return indexCount; }
            set { indexCount = value; }
        }

        #endregion


        #region Constructors

        public Mesh(MeshContainer cont, DeviceContextBase context)
        {

            this.context = context;
            this.container = container;
            this.CreateBuffer();
            LoadTextures(cont);
            LoadVertexBuffer(cont);
            LoadIndexBuffer(cont);
        }

        #endregion


        #region Events

        #endregion


        #region Methods

        private void CreateBuffer()
        {
            switch (this.Context.DXVersion)
            {
                case 9:
                    this.vertexBuffer = new DX9DynamicVertexBuffer<TexturedVertex>(context as DX9DeviceContext);
                    this.indexBuffer = new DX9DynamicIndexBuffer<Index>(context as DX9DeviceContext);
                    break;
                case 10:
                    //TODO: Implement for DX10
                    break;
                case 11:
                    //TODO: Implement for DX11
                    break;
            }


        }

        public void UpdateAnimation(float frameTime)
        {
            this.frameTime = frameTime;
            
            //int aniMatrixNum = (30 * frameTime) % this.container. numOfAnimations;

            //foreach (Bone bone in bones)
            //{
            //    // Just assign the final matrix from the animation matrices.
            //    bone.finalMatrix = bone.animationMatrices[aniMatrixNum];

            //    // Also use parent matrix if we got one
            //    // This will always work because all the bones are in order.
            //    if (bone.parent != null)
            //        bone.finalMatrix *=
            //            bone.parent.finalMatrix;
            //}

        }

        public abstract void LoadTextures(MeshContainer m);

        public abstract void LoadVertexBuffer(MeshContainer m);

        public abstract void LoadIndexBuffer(MeshContainer m);

        public abstract void Render();

        #endregion


    }
}
